/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package czStvDpds.graphics3D;

import czStvDpds.graphics3D.geometry.Texture;
import czStvDpds.graphics3D.geometry.TextureEnvironment;
import czStvDpds.graphics3D.geometry.TextureProperties;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.util.vector.Matrix4f;

/**
 *
 * @author divad
 */
public class TextureUnitSettings {

    private int textureUnitNumber;
    private int texGenSType = -1;
    private int texGenTType = -1;
    private int texGenRType = -1;
    private int texGenQType = -1;
    private boolean sTexgenEnabled = false;
    private boolean tTexgenEnabled = false;
    private boolean rTexgenEnabled = false;
    private boolean qTexgenEnabled = false;
    private int usedTextureType = -1;
    private static FloatBuffer matrixStorer;
    private TextureEnvironment env;
    private boolean clientTextureEnabled = false;
    private static TextureEnvironment baseEnvironment = new TextureEnvironment();
    private static TextureProperties baseProperties = new TextureProperties();

    public TextureUnitSettings(int textureUnitNumber) {
        this.textureUnitNumber = textureUnitNumber;
        matrixStorer = BufferUtils.createFloatBuffer(16);
        this.env = new TextureEnvironment();
    }

    public boolean isrTexgenEnabled() {
        return rTexgenEnabled;
    }

    public boolean issTexgenEnabled() {
        return sTexgenEnabled;
    }

    public boolean istTexgenEnabled() {
        return tTexgenEnabled;
    }

    public int getTexGenRType() {
        return texGenRType;
    }

    public int getTexGenSType() {
        return texGenSType;
    }

    public int getTexGenTType() {
        return texGenTType;
    }

    public int getTextureUnitNumber() {
        return textureUnitNumber;
    }

    public boolean isClientTexCoordsEnabled() {
        return clientTextureEnabled;
    }

    public int getUsedTextureType() {
        return usedTextureType;
    }

    public void setClientTextureEnabled(boolean enabled) {
        GL13.glClientActiveTexture(GL13.GL_TEXTURE0 + this.textureUnitNumber);
        if (this.clientTextureEnabled == true && enabled == false) {
            GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
        } else if (this.clientTextureEnabled == false && enabled == true) {
            GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
        }
        this.clientTextureEnabled = enabled;
    }

    public void adjustGLToText() {
        GL13.glActiveTexture(GL13.GL_TEXTURE0 + textureUnitNumber);
        GL11.glMatrixMode(GL11.GL_TEXTURE);
        new Matrix4f().setIdentity().store(matrixStorer);
        matrixStorer.rewind();
        GL11.glLoadMatrix(matrixStorer);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);

        this.adjustTexGen(TextureUnitSettings.baseProperties);
        this.adjustEnvironment(TextureUnitSettings.baseEnvironment);

        if (this.usedTextureType != TextureProperties.TEXTURE_2D) {
            if (this.usedTextureType != -1) {
                GL11.glDisable(this.usedTextureType);
            }
            this.usedTextureType = TextureProperties.TEXTURE_2D;
            GL11.glEnable(this.usedTextureType);
        }
    }

    public void adjustGLToTexture(Texture texture) {
        GL13.glActiveTexture(GL13.GL_TEXTURE0 + textureUnitNumber);
        GL11.glMatrixMode(GL11.GL_TEXTURE);
        texture.getMatrix().store(matrixStorer);
        matrixStorer.rewind();
        GL11.glLoadMatrix(matrixStorer);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);

        this.adjustTexGen(texture.getProperties());
        this.adjustEnvironment(texture.getEnvironment());

        if (this.usedTextureType != texture.getProperties().getType()) {
            if (this.usedTextureType != -1) {
                GL11.glDisable(this.usedTextureType);
            }
            this.usedTextureType = texture.getProperties().getType();
            GL11.glEnable(this.usedTextureType);
        }

    }

    private void adjustEnvironment(TextureEnvironment tenv) {
//        TextureEnvironment tenv = texture.getEnvironment();

//        System.out.println("change environment");
        if (env.getEnvironmentMode() != tenv.getEnvironmentMode()) {
            env.setEnvironmentMode(tenv.getEnvironmentMode());
            GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, env.getEnvironmentMode());
            System.out.println("change environment");
        }
        if (env.getEnvironmentMode() == TextureEnvironment.ENVMODE_COMBINE) {
            ///////////////////////rgb////////////////////////
            if (env.getCombineModeRGB() != tenv.getCombineModeRGB()) {
                env.setCombineModeRGB(tenv.getCombineModeRGB());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_COMBINE_RGB, env.getCombineModeRGB());
            }
            if (env.getSource0RGB() != tenv.getSource0RGB()) {
                env.setSource0RGB(tenv.getSource0RGB());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_SOURCE0_RGB, env.getSource0RGB());
            }
            if (env.getSource1RGB() != tenv.getSource1RGB()) {
                env.setSource1RGB(tenv.getSource1RGB());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_SOURCE1_RGB, env.getSource1RGB());
            }
            if (env.getSource2RGB() != tenv.getSource2RGB()) {
                env.setSource2RGB(tenv.getSource2RGB());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_SOURCE2_RGB, env.getSource2RGB());
            }
            if (env.getOperand0RGB() != tenv.getOperand0RGB()) {
                env.setOperand0RGB(tenv.getOperand0RGB());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_OPERAND0_RGB, env.getOperand0RGB());
            }
            if (env.getOperand1RGB() != tenv.getOperand1RGB()) {
                env.setOperand1RGB(tenv.getOperand1RGB());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_OPERAND1_RGB, env.getOperand1RGB());
            }

            //////////////alpha//////////////////////////
            if (env.getCombineModeALPHA() != tenv.getCombineModeALPHA()) {
                env.setCombineModeALPHA(tenv.getCombineModeALPHA());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_COMBINE_ALPHA, env.getCombineModeALPHA());
            }
            if (env.getSource0ALPHA() != tenv.getSource0ALPHA()) {
                env.setSource0ALPHA(tenv.getSource0ALPHA());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_SOURCE0_ALPHA, env.getSource0ALPHA());
            }
            if (env.getSource1ALPHA() != tenv.getSource1ALPHA()) {
                env.setSource1ALPHA(tenv.getSource1ALPHA());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_SOURCE1_ALPHA, env.getSource1ALPHA());
            }
            if (env.getSource2ALPHA() != tenv.getSource2ALPHA()) {
                env.setSource2ALPHA(tenv.getSource2ALPHA());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_SOURCE2_ALPHA, env.getSource2ALPHA());
            }
            if (env.getOperand0ALPHA() != tenv.getOperand0ALPHA()) {
                env.setOperand0ALPHA(tenv.getOperand0ALPHA());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_OPERAND0_ALPHA, env.getOperand0ALPHA());
            }
            if (env.getOperand1ALPHA() != tenv.getOperand1ALPHA()) {
                env.setOperand1ALPHA(tenv.getOperand1ALPHA());
                GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL13.GL_OPERAND1_ALPHA, env.getOperand1ALPHA());
            }
        }
        if (env.getEnvironmentColor().compareTo(tenv.getEnvironmentColor()) != 0) {
            env.setEnvironmentColor(tenv.getEnvironmentColor());
            GL11.glTexEnv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, env.getEnvironmentColor());
        }
    }

    private void adjustTexGen(TextureProperties tp) {
        // nastavení generování texturových koordinátů S.
        if (tp.issTexgenEnabled()) {
            if (this.sTexgenEnabled == false) {
                this.sTexgenEnabled = true;
                GL11.glEnable(GL11.GL_TEXTURE_GEN_S);
            }
            if (tp.getTexGenSType() != this.texGenSType) {
                this.texGenSType = tp.getTexGenSType();
                GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, texGenSType);
            }
            if (tp.getTexGenSType() != GL11.GL_SPHERE_MAP) {
                GL11.glTexGen(GL11.GL_S, texGenSType == GL11.GL_EYE_LINEAR ? GL11.GL_EYE_PLANE : GL11.GL_OBJECT_PLANE, tp.getTexGenSPlane());
            }
        } else {
            if (this.sTexgenEnabled == true) {
                GL11.glDisable(GL11.GL_TEXTURE_GEN_S);
            }
        }

        // nastavení generování texturových koordinátů T.
        if (tp.istTexgenEnabled()) {
            if (this.tTexgenEnabled == false) {
                this.tTexgenEnabled = true;
                GL11.glEnable(GL11.GL_TEXTURE_GEN_T);
            }
            if (tp.getTexGenTType() != this.texGenTType) {
                this.texGenTType = tp.getTexGenTType();
                GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, texGenTType);
            }
            if (tp.getTexGenTType() != GL11.GL_SPHERE_MAP) {
                GL11.glTexGen(GL11.GL_T, texGenTType == GL11.GL_EYE_LINEAR ? GL11.GL_EYE_PLANE : GL11.GL_OBJECT_PLANE, tp.getTexGenTPlane());
            }
        } else {
            if (this.tTexgenEnabled == true) {
                GL11.glDisable(GL11.GL_TEXTURE_GEN_T);
            }
        }

        // nastavení generování texturových koordinátů R.
        if (tp.isrTexgenEnabled()) {
            if (this.rTexgenEnabled == false) {
                this.rTexgenEnabled = true;
                GL11.glEnable(GL11.GL_TEXTURE_GEN_R);
            }
            if (tp.getTexGenRType() != this.texGenRType) {
                this.texGenRType = tp.getTexGenRType();
                GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, texGenRType);
            }
            if (tp.getTexGenRType() != GL11.GL_SPHERE_MAP) {
                GL11.glTexGen(GL11.GL_R, texGenRType == GL11.GL_EYE_LINEAR ? GL11.GL_EYE_PLANE : GL11.GL_OBJECT_PLANE, tp.getTexGenRPlane());
            }
        } else {
            if (this.rTexgenEnabled == true) {
                GL11.glDisable(GL11.GL_TEXTURE_GEN_R);
            }
        }

        // nastavení generování texturových koordinátů Q.
        if (tp.isqTexgenEnabled()) {
            if (this.qTexgenEnabled == false) {
                this.qTexgenEnabled = true;
                GL11.glEnable(GL11.GL_TEXTURE_GEN_Q);
            }
            if (tp.getTexGenQType() != this.texGenQType) {
                this.texGenQType = tp.getTexGenQType();
                GL11.glTexGeni(GL11.GL_Q, GL11.GL_TEXTURE_GEN_MODE, texGenQType);
            }
            if (tp.getTexGenQType() != GL11.GL_SPHERE_MAP) {
                GL11.glTexGen(GL11.GL_Q, texGenQType == GL11.GL_EYE_LINEAR ? GL11.GL_EYE_PLANE : GL11.GL_OBJECT_PLANE, tp.getTexGenQPlane());
            }
        } else {
            if (this.qTexgenEnabled == true) {
                GL11.glDisable(GL11.GL_TEXTURE_GEN_Q);
            }
        }
    }

    public void disable() {
        if (this.usedTextureType != -1) {
            GL13.glActiveTexture(GL13.GL_TEXTURE0 + textureUnitNumber);
            GL11.glDisable(this.usedTextureType);
            this.usedTextureType = -1;
        }
    }
}
